home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 January: Mac OS SDK / Dev.CD Jan 97 SDK2.toast / Development Kits (Disc 2) / OpenDoc / OpenDoc Development / Debugging Support / OpenDoc™ Source Code / Storage / Bento / CM / DynValus.h < prev    next >
Encoding:
Text File  |  1996-08-28  |  25.4 KB  |  444 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        DynValus.h
  3.  
  4.     Contains:    Container Manager Dynamic Value Interfaces
  5.  
  6.     Written by:    Ira L. Ruben
  7.  
  8.     Owned by:    Ed Lai
  9.  
  10.     Copyright:    © 1992 - 1996 by Apple Computer, Inc., all rights reserved.
  11.  
  12.     Change History (most recent first):
  13.  
  14.          <2>     1/15/96    TJ        Cleaned Up
  15.          <2>     8/26/94    EL        #1181622 Ownership update.
  16.          <2>      5/9/94    MB        #1162181: Changes necessary to install MMM.
  17.          <1>      2/3/94    EL        first checked in
  18.  
  19.     To Do:
  20. */
  21.  
  22. /*---------------------------------------------------------------------------*
  23.  |                                                                           |
  24.  |                          <<<   DynValus.h    >>>                          |
  25.  |                                                                           |
  26.  |                Container Manager Dynamic Value Interfaces                 |
  27.  |                                                                           |
  28.  |                               Ira L. Ruben                                |
  29.  |                                  5/5/92                                   |
  30.  |                                                                           |
  31.  |                     Copyright Apple Computer, Inc. 1992-1994              |
  32.  |                           All rights reserved.                            |
  33.  |                                                                           |
  34.  *---------------------------------------------------------------------------*
  35.  
  36.  Dynamic values are special values which "know" how to manipulate on their own value data.
  37.  They do this through a set of value operation handlers which are expected to be
  38.  semantically the same as the standard API value operations.
  39.  
  40.  The following value operations are expected to be supported by these handlers:
  41.  
  42.  CMSize CMGetValueSize(CMValue value);
  43.  CMSize CMReadValueData(CMValue value, CMPtr buffer, CMCount offset, CMSize maxSize,
  44.                                                  CMType *type);
  45.  void CMWriteValueData(CMValue value, CMPtr buffer, CMCount offset, CMSize size);
  46.  void CMInsertValueData(CMValue value, CMPtr buffer, CMCount offset, CMSize size);
  47.  void CMDeleteValueData(CMValue value, CMCount offset, CMSize size);
  48.  void CMGetValueInfo(CMValue value, CMContainer *container, CMObject *object,
  49.                                          CMProperty *property, CMType *type, CMGeneration *generation);
  50.  void CMSetValueType(CMValue value, CMType type);
  51.  void CMSetValueGeneration(CMValue value, CMGeneration generation);
  52.  void CMReleaseValue(CMValue);
  53.  
  54.  Whenever a dynamic value is passed to a standard API value routine corresponding to the
  55.  above handlers, the handler is called instead.  That is why the handler must be
  56.  semantically identical.
  57.  
  58.  Basically, dynamic values are similar to C++ objects where the handlers are the object's
  59.  methods.  They are dynamic in the sense that they only exist from creation (discussed
  60.  below) and last until until they are released (CMReleaseValue()).
  61.  
  62.  A dynamic value can have its own data (similar to C++ class fields).  The data is
  63.  generally used to create the handler's refCon during dynamic value creation.
  64.   
  65.  A dynamic value results when a value is created by to CMNewValue() or attempted to be
  66.  used by CMUseValue(), and the following two conditions occur:
  67.  
  68.      1. The type or any of its base types (if any, created by CMAddBaseType()), are for
  69.           global names that have associated metahandlers registered by CMRegisterType().
  70.          
  71.     2. The metahandlers support the operation type to return a "use value" handler, and
  72.          in addition for CMNewValue(), a "new value" handler.
  73.  
  74.  The "new value" handlers are used to define initialization data for the "use value"
  75.  handlers.  The "use value" handlers are called to set up and return a refCons.  Another
  76.  metahandler address is also returned. This is used to get the address of the value
  77.  operation handlers corresponding to the standard API CM... value routines mentioned above.
  78.  
  79.  Just like C++, dynamic values may be "subclassed" via their (base) types.  If a handler
  80.  for a particular operation is not defined for a value, its "base value" is used to get the
  81.  "inherited" handler.  This continues up a dynamic value's chain of base values, up to the
  82.  original "real" value that spawned the base values from the CMNewValue() or CMUseValue().
  83.  
  84.  Thus for each dynamic value, there is a vector of handler addresses.    DynValus.h   
  85.  defines the layout of that vector.  Also defined there are the other interfaces needed to
  86.  process a dynamic value by the API routines themselves.  The routines themselves are in
  87.  this file.
  88.  
  89.  The vector becomes part of a set of "extensions" to the dynamic value header.  The
  90.  extensions struct is defined in  TOCEnts.h   along with the other value header
  91.  definitions.  The dynamic value stuff is kept separate because it is sufficiently
  92.  distinct.
  93.  
  94.  For a full description of the dynamic value data structures and how dynamic values work
  95.  see DynamicValues.c.  It's "everything you wanted to know about dynamic values and
  96.  afraid to ask" kind of description.
  97.   
  98.  Implementation note: This header is slightly different from the other headers in its
  99.                                              organization.  This is due to the complexity involved with dynamic
  100.                                             values.  The various declarations are ordered such that this reads
  101.                                             as a description from top to bottom.  They are not just as set of
  102.                                             isolated (but related) definitions which is generally the case in
  103.                                             the other headers.  So this file is best understood by reading it 
  104.                                             in the order presented.
  105. */
  106.  
  107. #ifndef __DYNAMICVALUES__
  108. #define __DYNAMICVALUES__
  109.  
  110. #include <stdarg.h>
  111.  
  112. #ifndef __CMTYPES__
  113. #include "CMTypes.h"
  114. #endif
  115. #ifndef __CM_API_TYPES__
  116. #include "CMAPITyp.h"
  117. #endif
  118.  
  119. struct Container;
  120. struct TOCObject;
  121. struct TOCValueHdr;
  122.  
  123.                                                                     CM_CFUNCTIONS
  124.  
  125. /* The following defines what each entry in the dynamic value vector looks like...            */
  126.  
  127. struct DynamicValueVectorEntries {        /* Layout of a dynamic value vector entry:                */
  128.     CMHandlerAddr handler;                            /*        the handler address                                                    */
  129.     CMValue                thisValue;                        /*        the handler's value (C++ "this")                        */
  130.     CMBoolean         active;                                /*        true ==> handler is in calling chain                */
  131. };
  132. typedef struct DynamicValueVectorEntries DynamicValueVectorEntries, *DynamicValueVectorEntriesPtr;
  133.  
  134. /* When a handler is called, it is expected to do its operations on the "base value" of    */
  135. /* the value passed to it.  It gets its base value using CMGetBaseValue().  However,        */
  136. /* we don't want to allow recursive use of the API for the same value.  That would            */
  137. /* call the handler again and we would be in an infinit loop!  Thus the active switch        */
  138. /* is provided to check for this so we can report an error.                                                            */
  139.  
  140. /* The vector is initialized with each handler address thisValue set to NULL.  On first */
  141. /* use we use the methandler returned from the "use value" handler (saved in the value     */
  142. /* header extensions) to get the proper handler address.  It is saved in the handler         */
  143. /* field of the vector entry. Remember we may have to search up through a dynamic value */
  144. /* chain to find an "inherited" method ('er, excuse me, value handler operation).  Thus */
  145. /* the handler used may correspond to a different dynamic value. We must therefore save */
  146. /* the dynamic value refNum along with the handler address (in the thisValue).  It is     */
  147. /* basically the C++ "this" pointer for the method (oops, sorry again, value handler         */
  148. /* operation).                                                                                                                                                    */
  149.  
  150. /* Of course, in the simplest case, where the handler is provided for the original             */
  151. /* value, the thisValue will point to its own dynamic value header.  At the other                */
  152. /* extreme no handlers are supplied for the operation and we end up using the "real"        */
  153. /* value that spawned the dynamic value(s).  In that case the handler pointer in the        */
  154. /* vector entry remains NULL and the thisValue will be the "real" value refNum.  With        */
  155. /* no handler we use the actual API routine to process the real value.                                    */
  156.  
  157. /* Now that you understand what each vector entry contains, we can define the vector        */
  158. /* itself...                                                                                                                                                        */
  159.  
  160. struct DynamicValueVector {
  161.     DynamicValueVectorEntries cmGetValueSize;
  162.     DynamicValueVectorEntries cmReadValueData;
  163.     DynamicValueVectorEntries cmWriteValueData;
  164.     DynamicValueVectorEntries cmInsertValueData;
  165.     DynamicValueVectorEntries cmDeleteValueData;
  166.     DynamicValueVectorEntries cmGetValueInfo;
  167.     DynamicValueVectorEntries cmSetValueType;
  168.     DynamicValueVectorEntries cmSetValueGen;
  169.     DynamicValueVectorEntries cmReleaseValue;
  170. };
  171. typedef struct DynamicValueVector DynamicValueVector;
  172.  
  173. /* Remember this becomes part of the extensions belonging only to a dynamic value header*/
  174. /* as defined in TOCEntries.h.                                                                                                                    */
  175.  
  176. /* Just as with standard handlers, to make it easier and more readable for the Container*/
  177. /* Manager to call the dynamic value handlers, we will use macros.  These macros will        */
  178. /* require the following typedefs as casts to convert the generic handler typedef,             */
  179. /* HandlerAddr (the type used to store the addresses in the vector), to the actual            */
  180. /* function type:                                                                                                                                                */
  181.  
  182. typedef CMSize (*TcmGetValueSize)(CMValue value);
  183. typedef CMSize (*TcmReadValueData)(CMValue value, CMPtr buffer, CMCount offset, CMSize maxSize);
  184. typedef void (*TcmWriteValueData)(CMValue value, CMPtr buffer, CMCount offset, CMSize size);
  185. typedef void (*TcmInsertValueData)(CMValue value, CMPtr buffer, CMCount offset, CMSize size);
  186. typedef void (*TcmDeleteValueData)(CMValue value, CMCount offset, CMSize size);
  187. typedef void (*TcmGetValueInfo)(CMValue value, CMContainer *container, CMObject *object,
  188.                                                                 CMProperty *property, CMType *type, 
  189.                                                                 CMGeneration *generation);
  190. typedef void (*TcmSetValueType)(CMValue value, CMType type);
  191. typedef void (*TcmSetValueGen)(CMValue value, CMGeneration generation);
  192. typedef void (*TcmReleaseValue)(CMValue);
  193.  
  194. /* Here now are the macros used to do the calls using the vector...                                            */
  195.  
  196. #define CMDynGetValueSize(v)                            (*(TcmGetValueSize)DYNEXTENSIONS(v)->dynValueVector.cmGetValueSize.handler)((CMValue)(v))
  197. #define CMDynReadValueData(v, b, x, m)        (*(TcmReadValueData)DYNEXTENSIONS(v)->dynValueVector.cmReadValueData.handler)((CMValue)(v), (CMPtr)(b), (CMCount)(x), (CMSize)(m))
  198. #define CMDynWriteValueData(v, b, x, n)        (*(TcmWriteValueData)DYNEXTENSIONS(v)->dynValueVector.cmWriteValueData.handler)((CMValue)(v),    (CMPtr)(b), (CMCount)(x), (CMSize)(n))
  199. #define CMDynInsertValueData(v, b, x, n)    (*(TcmInsertValueData)DYNEXTENSIONS(v)->dynValueVector.cmInsertValueData.handler)((CMValue)(v), (CMPtr)(b), (CMCount)(x), (CMSize)(n))
  200. #define CMDynDeleteValueData(v, x, n)            (*(TcmDeleteValueData)DYNEXTENSIONS(v)->dynValueVector.cmDeleteValueData.handler)((CMValue)(v), (CMCount)(x), (CMSize)(n))
  201. #define CMDynGetValueInfo(v,c,obj,p,t, g) (*(TcmGetValueInfo)DYNEXTENSIONS(v)->dynValueVector.cmGetValueInfo.handler)((CMValue)(v), (CMContainer*)(c), (CMObject*)(obj),\
  202.                                                                                                                                                                                                                                         (CMProperty*)(p), (CMType*)(t), (CMGeneration*)(g))
  203. #define CMDynSetValueType(v, t)                          (*(TcmSetValueType)DYNEXTENSIONS(v)->dynValueVector.cmSetValueType.handler)((CMValue)(v), (CMType)(t))
  204. #define CMDynSetValueGen(v, g)                         (*(TcmSetValueGen)DYNEXTENSIONS(v)->dynValueVector.cmSetValueGen.handler)((CMValue)(v), (CMGeneration)(g))
  205. #define CMDynReleaseValue(v)                            (*(TcmReleaseValue)DYNEXTENSIONS(v)->dynValueVector.cmReleaseValue.handler)((CMValue)(v))
  206.  
  207. /* If nothing else, the above shows that, with enough casts, you can get away with             */
  208. /* anything in C!  Aren't casts wonderful?  Repeat after me -- casts are your friend.        */
  209.  
  210. /* As mentioned earlier, each corresponding API value operation must check to see if it    */
  211. /* has a dynamic value and call the corresponding handler which does the operation. It    */
  212. /* must get the proper address on first use.  It must set switches to mark the handler    */
  213. /* as active.  It must also set a switch to allow CMGetBaseValue() calls which are only    */
  214. /* allowed from dynamic value handlers.  Thus the algorithm looks something like this     */
  215. /* (ignoring all errors for the moment):                                                                                                */
  216.  
  217. /*    if (IsDynamicValue(v)) {                                                                                                                        */
  218. /*        v = GetDynHandlerAddress(v, h, g);                                                                                                */
  219. /*        if (IsDynamicValue(v)) {                                                                                                                    */
  220. /*            SignalDynHandlerInUse(v, h);                                                                                                        */
  221. /*            AllowCMGetBaseValue(container);                                                                                                    */
  222. /*                                                                                                                                                                            */
  223. /*            Call the proper dynamic value handler with one of the above macros definitions.    */
  224. /*             The macro will pass the appropriate value corresponding to a possibly inherited    */
  225. /*             handler.  If the handler returns a value save it to be returned as the result.    */
  226. /*                                                                                                                                                                            */
  227. /*            DisAllowCMGetBaseValue(container);                                                                                            */
  228. /*            SignalDynHandlerAvailable(v, h);                                                                                                */
  229. /*            return [result];                                                                                                                                */
  230. /*        }                                                                                                                                                                    */
  231. /*    }                                                                                                                                                                        */
  232.  
  233. /* In the above algorithm,                                                                                                                             */
  234. /*        v is a dynamic CMValue (note that GetDynHandlerAddress may CHANGE it),                         */
  235. /*        h is a pointer to a vector entry in the extensions,                                                             */
  236. /*        g is the metahandlers operation type string,                                                                            */
  237.  
  238. /* The GetDynHandlerAddress() takes a vector entry and sets the handler address as a        */
  239. /* function of the "g" metahandler operation code.  On first call it will search for the*/
  240. /* inherited method if necessary.     The vector is updated with the found handler address    */
  241. /* and the associated "this" value saved.  This is the value returned and whose switches*/
  242. /* we set.  We do the call and reset the switches, all using the same "this" value.            */
  243.  
  244. /* Note, in the limit, the search for the inherited handler may end up finding the             */
  245. /* original "real" value that spawned the dynamic values!  Thus what is returned from        */
  246. /* GetDynHandlerAddress() in this case is a "real" value to be operated upon using the    */
  247. /* standard API routine itself.  That is why a second IsDynamicValue() must be done to    */
  248. /* bypass the handler call and switch setting/resetting.                                                                */
  249.  
  250. /* Be careful here!  Since there is no guarantee the value coming back from the                    */
  251. /* GetDynHandlerAddress() call is the one that went in, the code must reload any copies    */
  252. /* of the value sometime following the GetDynHandlerAddress() calls. This is highlighted*/
  253. /* as something to look out for because it has already caused one bug!                                    */
  254.  
  255. /* All of the above is what each corresponding API value operation must do.  Given all     */
  256. /* this, it is impossible to write a generalized macro to minimize the coding. We could */
  257. /* write a unique macro for each handler just as the vector calls are done above, but         */
  258. /* that would probably be confusing.                                                                                                         */
  259.  
  260. /* So as a comprimise, the following macros are defined.  They basically mimic the            */
  261. /* above algorithm, but here take errors into account.                                                                    */
  262.  
  263. #define GetDynHandlerAddress(v, h, g, s, x) if ((v = cmGetDynHandlerAddress((CMValue)(v), &DYNEXTENSIONS(v)->dynValueVector.h, (CMGlobalName)(g), s)) == NULL) \
  264.                                                                                             return x
  265. #define SignalDynHandlerInUse(v, h)                     DYNEXTENSIONS(v)->dynValueVector.h.active = true
  266. #define SignalDynHandlerAvailable(v, h)             DYNEXTENSIONS(v)->dynValueVector.h.active = false
  267. #define AllowCMGetBaseValue(container)            ++((ContainerPtr)(container))->getBaseValueOk
  268. #define DisAllowCMGetBaseValue(container)        if (--((ContainerPtr)(container))->getBaseValueOk < 0) \
  269.                                                                                             ((ContainerPtr)(container))->getBaseValueOk = 0;
  270.  
  271. /* The IsDynamicValue() call is defined in TOCEntries.h.                                                                */
  272.  
  273. /* The "h" in all these macros is the vector entry name.                                                                */
  274.  
  275. /* The "x" parameter in GetDynHandlerAddress has the same purpose as in    ErrorRpt.h   */
  276. /* where we return CM_NOVALUE, NULL, or whatever is appropriate to indicate failure of    */
  277. /* the API routine.                                                                                                                                            */
  278.  
  279. /* Also for GetDynHandlerAddress, the "s" is the name of the API routine doing the call.*/
  280. /* This is used by cmGetDynHandlerAddress() simply to use as an insert if it should         */
  281. /* report an error prior to returning NULL.                                                                                            */
  282.  
  283. /* Note the AllowCMGetBaseValue and DisAllowCMGetBaseValue macros. As mentioned earlier,*/
  284. /* a CMGetBaseValue() is only allowed from value operation handlers.  The two macros        */
  285. /* control a single switch, getBaseValueOk, the CMGetBaseValue() checks.  The switch is    */
  286. /* actualy a counter which, just to be safe, is never allowed to stay negative.  0 means*/
  287. /* CMGetBaseValue() is illegal.  Greater than 0, it's legal.  The reason the switch is a*/
  288. /* counter is because dynamic values use CMGetBaseValue() to do their operations in         */
  289. /* terms of their base values. If a dynamic value's base is also dynamic (i.e., we have */
  290. /* layered dynamic values), then we have a nesting condition.  Hence the counter.                */
  291.  
  292. /* The rest of this header is more "normal", i.e., a collection of related definitions    */
  293. /* and function headers.                                                                                                                                */
  294.  
  295.     
  296. struct TOCValueHdr *cmFollowTypes(struct TOCValueHdr *theBaseValueHdr,
  297.                                                                     struct TOCObject *type,
  298.                                                                     CMBoolean isNewValue, va_list *constructorData);
  299.     /*
  300.     This routine creates a dynamic value layers for the passed type and all of its base types,
  301.     if any of these types have a "use value" handler.  This routine is only called by
  302.     CMNewValue() or CMUseValue().  For CMNewValue(), "metadata" handler and "new value"
  303.     handlers are also required.  The top-most dynamic value header pointer is returned.  This
  304.     should be returned from CMUseValue() or CMNewValue().  NULL is returned if an error is
  305.     reported.  The original "real" value is returned if no dynamic values are created.
  306.      
  307.     For CMUseValue(), isNewValue should be set to false.  It should only be set to true for
  308.     CMNewValue().  Also for CMNewValue(), the constructorData must point at the CMNewValue()
  309.     "..." parameters.  These are consumed as the base type metadata (returned from the 
  310.     "metadata" handler) describes how to create data packets from the "..." parameters.  The
  311.     packets, in turn, are passed to the "new value" handlers.  A "new value" handler uses its
  312.     data packet to write (possibly different) data to its base value.  This written data will
  313.     then be read and used by the "use value" handler.
  314.     
  315.     The "use value" handler is called for both the CMUseValue() and CMNewValue() cases.  If
  316.     it's companion "new value" handler wrote data to its base value, the "use value" handler
  317.     will probably read the data to create its refCon.  The refCon will be passed to all
  318.     value handlers.  The "use value" handler returns its refCon along with another
  319.     metahandler address that is used to get the value handler addresses.  These are then
  320.     used to create the dynamic value.
  321.     
  322.     See dynamic value documentation in   DynValus.c    for a full a description of the
  323.     prototypes for the "metadata", "new value", and "use value" handlers, as well as the
  324.     description of the metadata itself.
  325.     
  326.     To produce all the required dynamic values, cmFollowTypes() recursively follows the
  327.     types, looking for base types as defined by CMAddBaseType().  Each type can have any
  328.     number of base types.  The recursion effectively produces a depth-first search of all
  329.     the base types.
  330.     
  331.     As each type is completed (i.e., no more base types for it), a dynamic value is created
  332.     as described above.  That is, for CMNewValue(), a type's "metadata" handler instructs us
  333.     on how many CMNewValue() "..." parameters to consume and how to construct their packet.
  334.     That is passed to the "new value" handler so it can write some appropriate data to the
  335.     base value.  The "use value" is called in all cases which reads the data written by "new
  336.     value" to construct its refCon.  The refCon is returned here along with the metahandler
  337.     address that will yield the value handler routine addresses.
  338.     
  339.     The refCon and metahandler address are passed to newDynamicValue() to construct one
  340.     dynamic value (layer).  The resulting dynamic value is used as the base value for the
  341.     next layer.  This produces the desired data structures.
  342.     
  343.     Note, because this routine searches through the types down to their leaves, and then
  344.     generates the dynamic values on the way back "up", the CMNewValue() "..." parameters
  345.     must be ordered for the "deepest" type first.  For example, given the following type
  346.     inheritance heirarchy (read these as T1 inherits from T2 and T3, and so on):
  347.     
  348.                                       T4      T5
  349.                                         *    *
  350.                                          *  *
  351.                                   T2      T3
  352.                                     *    *
  353.                                      *  *
  354.                                       T1
  355.                              
  356.     The depth-first search, starting at T1, yields the sequence: T2 T4 T5 T3 T1.  Then this
  357.     is the order the CMNewValue() "..." parameters must be in.
  358.     */
  359.     
  360.     
  361. CMValue cmGetDynHandlerAddress(CMValue value, DynamicValueVectorEntriesPtr vectorEntry,
  362.                                                              CMconst_CMGlobalName operationType, char *routineName);
  363.     /*
  364.     A dynamic value handler is callable if it exists (of course!) and it is not being used
  365.     recursively.  The vectorEntry points to the dynamic value entry in its vector belonging
  366.     to the extensions of the passed dynamic value.  If this is not the first use of the
  367.     handler, the vector entry contains the handler address and its associated ("this") value
  368.     (discussed below).  If it is first use, cmGetDynHandlerAddress() must find the
  369.     ("inherited") handler address and its associated "this" value.
  370.     
  371.     No matter which case it is, the "this" value is returned as the function result.  NULL
  372.     is returned if an error is reported (discussed later).
  373.      
  374.     The returned value, and the one saved in the vector entry may not be the same.  They are
  375.     if the passed value has a handler.  If it doesn't, an "inherited" handler, from one of
  376.     the dynamic value's base values is used. The value associated for whoever has the handler 
  377.     is the "owning" value.  In C++ terms, it is the "this" pointer.
  378.     
  379.     In the limit, we could end up using the original "real" value that spawned the dynamic
  380.     value(s).  In that is indeed the case, we end up using the calling routine which will
  381.     always be an API value operation (as shown in the algorithm above).
  382.  
  383.     The found handler address and "this" pointer are saved in the passed dynamic value's
  384.     vector entry so we don't have to do the search on successive uses.  The "this" pointer
  385.     and handler address are also saved in the vector entry corresponding to "this" (unless,
  386.     of course, it is the "real" value).
  387.      
  388.     In the vector entry there is also a boolean flag that tells us whether the handler is
  389.     currently active, i.e., in the call chain.  If it is we have a recursion attempt.  This
  390.     causes an error report and NULL to be returned.  Since we will always find the handler
  391.     or use the "real" value, we can never get an error from that.  The recursion is the only
  392.     error condition.
  393.     */
  394.  
  395. CM_ULONG cmVScanDataPacketGuts(struct TOCObject *type, CM_CHAR *metaData,
  396.                                                              CM_UCHAR *dataPacket, va_list dataInitParams);
  397.     /*
  398.     This routine is the "guts" of the routine CMScanDataPacket().  It is used to extract the
  399.     fields of a data packet created from CMNewValue() "..." parameters according to the
  400.     specified metadata and place it in the "dataInitParams" parameters.  Each dataInitParams
  401.     parameter must be a pointer; extracted data read from the data packet are stored into the
  402.     locations pointed to by the pointers.
  403.     
  404.     The Container Manager accesses the metadata through a "metadata" handler for the type to
  405.     build the data packet.  cmVScanDataPacket() inverts the operation and allows a "new
  406.     value" handler to extract the data back into distinct variables. The "new value" handler
  407.     can use its own "metadata" handler to pass to the CMScanDataPacket() routine to extract
  408.     the data.
  409.     
  410.     The function returns the number of data items extracted and assigned to the parameters.
  411.     This could be 0 if the type does not have any metadata (or if an error is reported).
  412.     
  413.     NULL may be passed as the dataPacket or metaData pointer to indicate there is no
  414.     metadata.  
  415.     
  416.     The metadata format is discussed in DynamicValues.c.  The only special case is for the
  417.     "%*s" format specification.  This generates a fixed length string (not null terminated)
  418.     of n characters, where n is determined from a parameter in the CMNewValue() "..."
  419.     paramters.  The value of n is explicitly written to the packet data in front of the
  420.     string.  For symmetry (and so we can determine the number of characters to extract from
  421.     the packet data), we return the value of n to an explict parameter pointer passed here.
  422.     Thus the parameter pointer list passed to this routine should be identical to the "..."
  423.     parameters passed to a CMNewValue() "..." parameter list (at least the portion
  424.     corresponding to this type).
  425.     */
  426.  
  427.  
  428. void cmDeleteAllDynamicValueLayers(struct TOCValueHdr *theValueHdr, CMBoolean freeValueHdr);
  429.     /*
  430.     This routine is used in two contexts; first, for error recovery to free all the memory
  431.     for a newly allocated dynamic value layer set, and second, when freeing the entire TOC
  432.     to make usre all memory for any "dangling" dynamic values are freed.
  433.     
  434.     The current top-most dynamic value layer is passed in theValueHdr.  The layers are
  435.     back-linked up to the base "real" value.  All the dynamic value memory on this chain are
  436.     freed.  If freeValueHdr is true, then we were creating dynamic values for CMNewValue().
  437.     In that case, the real value itself is freed.  Really freed!  Not marked free as is the
  438.     usual case.
  439.     */
  440.  
  441.  
  442.                                                          CM_END_CFUNCTIONS
  443. #endif
  444.